#include "stackapp.h"

extern func_LinkStack fun_LinkStack;

/**
 * 功 能：
 *      判断是否为数字
 * 参 数：
 *      ch:要判断的字符
 * 返回值：
 *      成功：true
 *      失败：false
 **/
bool StackApp_isNumber(char ch)
{
    return !(('0' <= ch && '9' >= ch));
}

/**
 * 功 能：
 *      判断是否为运算符
 * 参 数：
 *      ch:要判断的字符
 * 返回值：
 *      成功：true
 *      失败：false
 **/
bool StackApp_isOperator(char ch)
{
    return !(('+' == ch || '-' == ch || '*' == ch || '/' == ch));
}

/**
 * 功 能：
 *      判断是否为左括号
 * 参 数：
 *      ch:要判断的字符
 * 返回值：
 *      成功：true
 *      失败：false
 **/
bool StackApp_isLeft(char ch)
{
    return !(('(' == ch));
}
/**
 * 功 能：
 *      判断是否为有括号
 * 参 数：
 *      ch:要判断的字符
 * 返回值：
 *      成功：true
 *      失败：false
 **/
bool StackApp_isRight(char ch)
{
    return !((')' == ch));
}

/**
 * 功 能：
 *      自定义优先级
 * 参 数：
 *      ch:要判断的字符
 * 返回值：
 *      优先级高：1
 *      优先级低：0
 *      异   常：-1
 **/
int StackApp_Priority(char ch)
{
    if (ch == '+' || ch == '-')
        return 1;
    else if (ch == '*' || ch == '/')
        return 2;
    else
        return -1;
}

/**
 * 功 能：
 *      中缀表达式转换成后缀表达式
 * 参 数：
 *      str:运算表达式
 *      out:转换后的后缀表达式输出
 * 返回值：
 *      成功：0
 *      失败：-1
 **/
int StackApp_Transform(const char *str, char *out)
{
    char *temp = (char *)str;
    if (str == NULL)
        return -1;

    char *buf = (char *)malloc(strlen(str) + 1);
    memset(buf, 0, strlen(str) + 1);
    char *pbuf = buf;

    Linklist *stack = fun_LinkStack.create();
    if (stack == NULL)
        return -1;

    while (*temp != '\0')
    {
        if (StackApp_isNumber(*temp) == true)
        {
            printf("%c ", *temp);
            strncpy(pbuf, temp, 1);
            pbuf++;
        }
        else if (StackApp_isOperator(*temp) == true)
        {
            while (StackApp_Priority(*temp) <= StackApp_Priority((char)((long)fun_LinkStack.top(stack))))
            {
                char ch = (char)(long)fun_LinkStack.pop(stack);
                printf("%c ", ch);
                strncpy(pbuf, (const char *)&ch, 1);
                pbuf++;
            }
            fun_LinkStack.push(stack, (LinkListNode *)(long)(*temp));
        }
        else if (StackApp_isLeft(*temp) == true)
        {
            fun_LinkStack.push(stack, (LinkListNode *)(long)(*temp));
        }
        else if (StackApp_isRight(*temp) == true)
        {
            while (StackApp_isLeft((char)(long)fun_LinkStack.top(stack)) != true)
            {
                char ch = (char)(long)fun_LinkStack.pop(stack);
                printf("%c ", ch);
                strncpy(pbuf, (const char *)&ch, 1);
                pbuf++;
            }
            fun_LinkStack.pop(stack);
        }
        else
        {
            if (*temp != ' ')
            {
                printf("Invalid expression! please retry\n");
                break;
            }
        }

        temp++;
    }

    while ((fun_LinkStack.length(stack) > 0) && (*temp == '\0'))
    {
        char ch = (char)(long)fun_LinkStack.pop(stack);
        printf("%c ", ch);
        strncpy(pbuf, (const char *)&ch, 1);
        pbuf++;
    }

    fun_LinkStack.destroy(stack);

    //printf("%s\n", buf);

    if (out != NULL)
    {
        strcpy(out, buf);
    }

    free(buf);

    return 0;
}

/**
 * 功 能：
 *      将字符转换成对应的数字
 * 参 数：
 *      ch:要转换的字符
 * 返回值：
 *      成功：输入字符的对应的数字
 *      失败：-1
 **/
int StackApp_Str2Int(char ch)
{
    return (ch <= '9' && ch >= '0') ? ch - '0' : -1;
}
/**
 * 功 能：
 *      将字符转换成对应的数字
 * 参 数：
 *      n  : 运算的左边值
 *      m  : 运算的右边值
 *      opt: 运算方式
 *      out: 输出结果    
 * 返回值：
 *      在 out 为 NULL 的时候
 *          如果计算正常，则返回值为计算结果
 *          如果计算不正常，则返回值为 -1
 *      在 out 不为 NULL 的时候
 *          如果计算正常，则返回值为 0
 *          如果计算不正常，则返回值为 -1
 *      特殊情况：
 *          如果 out 为NULL，并且返回值为-1，那么此时的-1有两种情况
 *              1、正常的计算结果
 *              2、异常返回
 **/
int StackApp_Operation(int l, int r, char opt, int *out)
{
    int ret = -1;
    switch (opt)
    {
    case '+':
        ret = l + r;
        break;
    case '-':
        ret = l - r;
        break;
    case '*':
        ret = l * r;
        break;
    case '/':
        ret = l / r;
        break;
    default:
        break;
    }

    if (out != NULL)
        *out = ret;

    return ret;
}

/**
 * 功 能：
 *      进行数学计算
 * 参 数：
 *      str:要计算的数学表达式，为后缀表达式形式
 *      out:计算结果输出
 * 返回值：
 *      在 out 为 NULL 的时候
 *          如果计算正常，则返回值为计算结果
 *          如果计算不正常，则返回值为 -1
 *      在 out 不为 NULL 的时候
 *          如果计算正常，则返回值为 0
 *          如果计算不正常，则返回值为 -1
 *      特殊情况：
 *          如果 out 为NULL，并且返回值为-1，那么此时的-1有两种情况
 *              1、正常的计算结果
 *              2、异常返回
 **/
int StackApp_Work(const char *str, int *out)
{
    if (str == NULL)
        return -1;

    char *temp = (char *)str;
    int ret = -1;

    LinkStack *stack = fun_LinkStack.create();
    if (stack == NULL)
        return -1;

    while (*temp != '\0')
    {
        if (StackApp_isNumber(*temp) == true)
        {
            fun_LinkStack.push(stack, (LinkStackNode *)(long)StackApp_Str2Int((*temp)));
        }
        else if (StackApp_isOperator(*temp) == true)
        {
            int right = ((int)(long)fun_LinkStack.pop(stack));
            int left = ((int)(long)fun_LinkStack.pop(stack));
            int value = 0;
            ret = StackApp_Operation((left), (right), *temp, &value);
            if (ret == -1)
                goto ERROR;

            fun_LinkStack.push(stack, (LinkListNode *)(long)value);
        }
        else
        {
            if (*temp != ' ')
            {
                goto ERROR;
            }
        }
        temp++;
    }
    if ((fun_LinkStack.length(stack) == 1) && (*temp == '\0'))
    {
        ret = (int)(long)fun_LinkStack.pop(stack);
    }
    else
    {
    ERROR:
        printf("Invalid expression! please retry\n");
    }

    fun_LinkStack.destroy(stack);
    if (out != NULL)
        *out = ret;

    return ret;
}

func_StackApp fun_StackApp = {
    // StackApp_isNumber,
    // StackApp_isOperator,
    // StackApp_isLeft,
    // StackApp_isRight,
    StackApp_Work,
    StackApp_Transform};
